﻿using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE80;
using EnvDTE;
using System.Collections;
using System.Text.RegularExpressions;
using QuickOpen.Framework.Items;
using QuickOpen.Framework.Comparers;

namespace QuickOpen.Framework.Repositories
{
    /// <summary>
    /// A IFilterableItem Repository to represent all physicial files in a Visual Studio Solution.
    /// </summary>
    public class FileRepository : IItemRepository
    {
        /// <summary>
        /// Returns all items found.
        /// </summary>
        public IFilterableItem[] Items
        {
            get { return _files.ToArray(); }
        }

        /// <summary>
        /// Creates a new instance of the FileRepository
        /// </summary>
        /// <param name="appObject">The DTE2 addin object representing the application</param>
        public FileRepository(DTE2 appObject)
        {
            Initialize(appObject);
        }

        private void Initialize(DTE2 appObject)
        {
            _files = new List<File>();

            Dictionary<string, bool> duplicateLookup = new Dictionary<string, bool>();
            Dictionary<string, File> filenameDuplicateLookup = new Dictionary<string, File>();

            foreach (Project p in appObject.Solution.Projects)
                if (p != null && p.ProjectItems != null)
                    FillFiles(p.ProjectItems, duplicateLookup, filenameDuplicateLookup);

            _files.Sort(new FileComparer(FileCompareType.CodePrefered));
        }

        private void FillFiles(ProjectItems p, Dictionary<string, bool> duplicateLookup, Dictionary<string, File> filenameDuplicateLookup)
        {
            foreach (ProjectItem pi in p)
            {
                File file = null;
                if (pi.Kind == Constants.vsProjectItemKindPhysicalFile)
                {
                    file = new File(pi);
                    file.FileRepository = this;

                    //Check if we have already processed this file.
                    if (!duplicateLookup.ContainsKey(file.FullPath.ToLower()))
                    {
                        file.IsDup = DoFilenameDupCheck(file, filenameDuplicateLookup);
                        _files.Add(file);
                        duplicateLookup.Add(file.FullPath.ToLower(), true);
                    }
                }

                if (pi.ProjectItems != null)
                    FillFiles(pi.ProjectItems, duplicateLookup, filenameDuplicateLookup);
            }
        }

        private bool DoFilenameDupCheck(File file, Dictionary<string, File> filenameDuplicateLookup)
        {
            if (filenameDuplicateLookup.ContainsKey(file.FileName.ToLower()))
            {
                filenameDuplicateLookup[file.FileName.ToLower()].IsDup = true;
                return true;
            }

            filenameDuplicateLookup[file.FileName.ToLower()] = file;
            return false;
        }

        /// <summary>
        /// Implementation of the IItemRepository query item.
        /// Will find the files that match and return them.
        /// </summary>
        /// <param name="query">The string query. Wildcards are accepted by this repository.</param>
        /// <returns>An array of the matching IFilterableItem items</returns>
        public IFilterableItem[] Query(string query)
        {
            if (string.IsNullOrEmpty(query))
                return _files.ToArray();

            Regex regex = CreateQueryRegularExpression(query);
            List<File> files = new List<File>();
            foreach (File file in _files)
                if (regex.IsMatch(file.FileName))
                    files.Add(file);

            return files.ToArray();
        }

        private Regex CreateQueryRegularExpression(string query)
        {
            string newQueryString = query
                .Replace("[", "\\[")
                .Replace("]", "\\]")
                .Replace("?", ".?")
                .Replace("*", ".*?")
                .Insert(0, "^");

            return new Regex(newQueryString, RegexOptions.IgnoreCase);
        }

        private List<File> _files;
    }
}
